﻿using Coevery.AppFramework.Metadata;
using Coevery.AppFramework.MetadataServiceReference;
using DevExpress.Utils;
using DevExpress.XtraEditors.Controls;
using DevExpress.XtraEditors.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DevExpress.XtraEditors;
using System.Collections.ObjectModel;

namespace Coevery.AppFramework.Extensions
{
    public class LookupListItem<T>
    {
        public string DisplayName { get; set; }
        public T Value { get; set; }
        public Guid PickListValueID { get; set; }
        public bool IsDeafult { get; set; }
    }

    public static class LookUpEditExtension
    {
        #region ComboBoxEdit
        public static void BindComboBoxList(this ComboBoxEdit comboBoxEdit, Entity entity, string attributeName)
        {
            comboBoxEdit.Properties.BindComboBoxList(entity, attributeName);
        }

        public static void BindComboBoxList(this RepositoryItemComboBox comboBoxEdit, Entity entity, string entityPropertyName)
        {
            var attribute = entity.Attributes
                .FirstOrDefault(a => a.PhysicalName.Equals(entityPropertyName));
            int langId = System.Globalization.CultureInfo.CurrentCulture.LCID;
            if (attribute != null && attribute.OptionSet != null)
            {
                var items = GetComboBoxListValues(attribute, langId);
                comboBoxEdit.Items.AddRange(items);
            }
        }

        private static List<ComboBoxItem> GetComboBoxListValues(EntityAttribute attribute, int langId)
        {
            var values = attribute.OptionSet.AttributePicklistValues.OrderBy(v => v.DisplayOrder);
            var items = new List<ComboBoxItem>();
            var labels = MetadataRepository.LocalizedLabels;
            foreach (var value in values)
            {

                var localizedLabels = labels.Where(l => l.ObjectId == value.AttributePicklistValueId);
                var localizedLabel = localizedLabels.FirstOrDefault(l => l.LanguageId == langId) ?? localizedLabels.First();
                if (localizedLabel != null)
                {
                    var item = new ComboBoxItem(value);
                    item.Value = localizedLabel.Label;
                    items.Add(item);
                }

            }
            if (attribute.IsNullable.HasValue && attribute.IsNullable.Value)
            {
                items.Insert(0, new ComboBoxItem(""));
            }
            return items;
        }
        #endregion
        #region LOOKUPEDIT  
        
        // HAy que cambiar el primer parametro de este metodo por un RepositoryLookUpEdit??s
        public static void BindPickList(this LookUpEdit lookUpEdit, Entity entity, Guid? parentPLV) 
        {
            if (parentPLV == null) 
            {
                BindPickList(lookUpEdit, entity);;
                return; 
            }
                
            if (lookUpEdit.DataBindings.Count == 0)
                return;

            var binding = lookUpEdit.DataBindings[0];
            string attributeName = binding.BindingMemberInfo.BindingMember;
            
            var attribute = entity.Attributes
                .FirstOrDefault(a => a.PhysicalName.Equals(attributeName));
            int langId = System.Globalization.CultureInfo.CurrentCulture.LCID;
            if (attribute != null && attribute.OptionSet != null)
            {
                var items = GetPickListValues(attribute, langId, parentPLV);
                InitializeLookUpEdit(lookUpEdit.Properties, items);
            }
        }
        
        public static void BindPickList(this LookUpEdit lookUpEdit, Entity entity)
        {
            if (lookUpEdit.DataBindings.Count == 0)
                return;

            var binding = lookUpEdit.DataBindings[0];
            string attributeName = binding.BindingMemberInfo.BindingMember;
            lookUpEdit.Properties.BindPickList(entity, attributeName);
        }

        // A MODIFICARRRRRR
        public static void BindPickList(this LookUpEdit lookUpEdit, ReadOnlyCollection<OptionSet> optionSetList, Guid? parentPLV)
        {
            
            string optionSetName = null;
            if (lookUpEdit.DataBindings.Count == 0) // Obtener databinding del nombre del LookUpEdit
            {
                optionSetName = lookUpEdit.Name;
            }
            else
            {
                var binding = lookUpEdit.DataBindings[0];
                optionSetName = binding.BindingMemberInfo.BindingMember;
            }
          
            // Joder como obtengo de esta lista por propery
            //OptionSet optionset = (OptionSet) (optionSetList.Where(e=>e.Name == optionSetName).First());            
            var optionset = optionSetList.Where(e => e.Name.Equals(optionSetName)).First();
            
            int langId = System.Globalization.CultureInfo.CurrentCulture.LCID;

            EntityAttribute attribute = new EntityAttribute();
            attribute.IsNullable = true;
            attribute.OptionSet = optionset;

            if (attribute != null && attribute.OptionSet != null)
            {
                var items = GetPickListValues(attribute, langId, parentPLV);
                InitializeLookUpEdit(lookUpEdit.Properties, items);  
            }
                    
        }

        public static void BindPickList(this LookUpEdit lookUpEdit, ReadOnlyCollection<OptionSet> optionSetList, Guid? parentPLV, string optionSetName)
        {
           
            var optionset = optionSetList.Where(e => e.Name.Equals(optionSetName)).First();

            int langId = System.Globalization.CultureInfo.CurrentCulture.LCID;

            EntityAttribute attribute = new EntityAttribute();
            attribute.IsNullable = true;
            attribute.OptionSet = optionset;

            if (attribute != null && attribute.OptionSet != null)
            {
                var items = GetPickListValues(attribute, langId, parentPLV);
                InitializeLookUpEdit(lookUpEdit.Properties, items);
            }

        }

        public static void BindLookupList(this LookUpEdit lookUpEdit, Entity entity, bool withEmptyRow)
        {
            if (lookUpEdit.DataBindings.Count == 0)
                return;

            var binding = lookUpEdit.DataBindings[0];
            string attributeName = binding.BindingMemberInfo.BindingMember;
            if (entity == null) return;
            var attribute = entity.Attributes.FirstOrDefault(a => a.PhysicalName.Equals(attributeName));
            if (attribute != null && attribute.AttributeLookupValues.Any())
            {
                var items = GetLookupValues(withEmptyRow, attribute, null);
                InitializeLookUpEdit(lookUpEdit.Properties, items);
            }
        }

        private static List<LookupListItem<Guid?>> GetLookupValues(bool withEmptyRow, EntityAttribute attribute, Guid? parentPLV)
        {
            var lookupValue = attribute.AttributeLookupValues.First();
            var lookupValueEntity = lookupValue.Entity;
            string displayMemberName =
                lookupValueEntity.Attributes.First(a => a.AttributeId == lookupValue.DisplayEntityAttributeId).PhysicalName;
            string valueMemberName = lookupValueEntity.Name + "Id";
            var values = new ODataObjectSpace().GetObjects(lookupValueEntity.PhysicalName);

            var items = new List<LookupListItem<Guid?>>();
            foreach (var value in values)
            {
                var item = new LookupListItem<Guid?>();
                object displayName = value.GetType().GetProperty(displayMemberName).GetValue(value, null);
                if (displayName != null)
                {
                    item.DisplayName = displayName.ToString();
                    //item.Value = (int)value.GetType().GetProperty(valueMemberName).GetValue(value, null); --> TODO CASCA TODO WARNING
                    item.Value = (Guid?)value.GetType().GetProperty(valueMemberName).GetValue(value, null); 
                    //item.PickListValueID  Creo que es para LookUpValues
                    items.Add(item);
                }
            }
            if (withEmptyRow)
            {
                items.Insert(0, new LookupListItem<Guid?>()/* { DisplayName = "", Value = new Guid() }*/);
            }
            return items;
        }
        #endregion

        #region RepositoryItemLookUpEdit

        public static void BindPickList(this RepositoryItemLookUpEdit lookUpEdit, Entity entity, string entityPropertyName)
        {
            var attribute = entity.Attributes
                .FirstOrDefault(a => a.PhysicalName.Equals(entityPropertyName));
            int langId = System.Globalization.CultureInfo.CurrentCulture.LCID;
            if (attribute != null && attribute.OptionSet != null)
            {
                var items = GetPickListValues(attribute, langId, null);

                InitializeLookUpEdit(lookUpEdit, items);
            }
        }

        public static void BindPickList(this RepositoryItemLookUpEdit lookUpEdit, EntityAttribute attribute)
        {
            int langId = System.Globalization.CultureInfo.CurrentCulture.LCID;
            if (attribute.OptionSet != null)
            {
                var items = GetPickListValues(attribute, langId, null);

                InitializeLookUpEdit(lookUpEdit, items);
            }
        }

        public static void InitializeLookUpEdit<T>(this RepositoryItemLookUpEdit lookUpEdit, List<LookupListItem<T>> items)
        {
            string displayMember = "DisplayName";
            string valueMember = "Value";
            //string valueMember = "AttributePicklistValueId";
            InitializeLookUpEdit(lookUpEdit, items, displayMember, valueMember);
            lookUpEdit.Columns.Clear();
            lookUpEdit.Columns.Add(new LookUpColumnInfo(lookUpEdit.DisplayMember));
            lookUpEdit.ShowHeader = false;
        }

        internal static void InitializeLookUpEdit(this RepositoryItemLookUpEditBase lookUpEdit, object datasource, string displayNameber, string valueMember)
        {
            lookUpEdit.DisplayMember = displayNameber;
            lookUpEdit.ValueMember = valueMember;
            lookUpEdit.DataSource = datasource;
            lookUpEdit.NullText = string.Empty;
            lookUpEdit.TextEditStyle = TextEditStyles.DisableTextEditor;
            lookUpEdit.ShowFooter = false;
            lookUpEdit.AllowNullInput = DefaultBoolean.True;
        }

        private static List<LookupListItem<int?>> GetPickListValues(EntityAttribute attribute, int langId, Guid? parentPLV)
        {
            System.Collections.Generic.IEnumerable<AttributePicklistValue> values;
            
            if (parentPLV != null)
            {
                values = attribute.OptionSet.AttributePicklistValues.OrderBy(x => x.DisplayOrder).Where(v => v.ParentAttributePickListValueId == parentPLV);
            }
            else
            {
                values = attribute.OptionSet.AttributePicklistValues.OrderBy(v => v.DisplayOrder);
            }
            
            List<LookupListItem<int?>> items = new List<LookupListItem<int?>>();
            
            foreach (var value in values)
            {
                var item = new LookupListItem<int?>();//TODO
                var localizedLabels = MetadataRepository.LocalizedLabels.Where(l => l.ObjectId == value.AttributePicklistValueId);
                var localizedLabel = localizedLabels.FirstOrDefault(l => l.LanguageId == langId) ?? localizedLabels.First();
                if (localizedLabel != null)
                {
                    item.DisplayName = localizedLabel.Label;
                    item.PickListValueID = localizedLabel.ObjectId;
                }
                item.Value = value.Value;
                items.Add(item);
            }
            //if (attribute.IsNullable.HasValue && attribute.IsNullable.Value) //Pendiente poder determinar si meto null discrecionalmente
            {
                items.Insert(0, new LookupListItem<int?>()/*{DisplayName = "", Value = -1}*/);
            }
            return items;
        }

       
        #endregion

        
    }
}
